// Collection of animation utility classes

// Underline
:root {
  --#{$prefix}underline-thickness: 1px;
}
@mixin underline(
  $border-width: var(--#{$prefix}underline-thickness),
  $element: after
) {
  position: relative;

  &::#{$element} {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: $border-width;
    content: "";
    background-color: currentcolor;
    transition: transform 0.3s ease-out;
    transform: scaleX(0);
    transform-origin: bottom right;
  }
}

@mixin underline-action($element: after) {
  &::#{$element} {
    transform: scaleX(1);
    transform-origin: bottom left;
  }
}

.animate-underline {
  &.animate-target,
  .animate-target {
    text-decoration: none;
    @include underline();
  }

  &:hover,
  &.show,
  &.active,
  &:focus-visible {
    &.animate-target,
    .animate-target {
      @include underline-action();
    }
  }
}

// Shake

.animate-shake {
  &:hover,
  &:focus-visible {
    .animate-target {
      animation: shake 0.8s;
    }
  }
}

@keyframes shake {
  0% {
    transform: scale3d(1, 1, 1);
  }
  20% {
    transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -5deg);
  }
  50%,
  70%,
  90% {
    transform: scale3d(1.25, 1.25, 1.25) rotate3d(0, 0, 1, 5deg);
  }
  60%,
  80% {
    transform: scale3d(1.25, 1.25, 1.25) rotate3d(0, 0, 1, -5deg);
  }
  100% {
    transform: scale3d(1, 1, 1);
  }
}

// Pulse

.animate-pulse {
  &:hover,
  &:focus-visible {
    .animate-target {
      animation: pulse 0.9s;
    }
  }
}

@keyframes pulse {
  0% {
    transform: scale(1);
  }
  14% {
    transform: scale(1.25);
  }
  28% {
    transform: scale(1);
  }
  42% {
    transform: scale(1.25);
  }
  70% {
    transform: scale(1);
  }
}

// Rotate

.animate-rotate {
  &:hover,
  &:focus-visible {
    .animate-target {
      animation: rotate 0.45s ease-in-out;
    }
  }
}

@keyframes rotate {
  from {
    transform: rotate(0);
  }
  to {
    transform: rotate(360deg);
  }
}

// Scale

.animate-scale {
  &:hover,
  &:focus-visible {
    .animate-target {
      animation: scale 0.35s ease-in-out;
    }
  }
}

@keyframes scale {
  0% {
    transform: scale3d(1, 1, 1);
  }

  50% {
    transform: scale3d(1.2, 1.2, 1.2);
  }

  100% {
    transform: scale3d(1, 1, 1);
  }
}

// Slide

@mixin slide($direction: end) {
  overflow: hidden;

  &:hover,
  &:focus-visible {
    .animate-target {
      animation: slide-#{$direction} 0.3s forwards;
    }
  }
}

.animate-slide-end {
  @include slide(end);
}

.animate-slide-start {
  @include slide(start);
}

.animate-slide-up {
  @include slide(up);
}

.animate-slide-down {
  @include slide(down);
}

@keyframes slide-end {
  49% {
    transform: translate(100%);
  }
  50% {
    opacity: 0;
    transform: translate(-100%);
  }
  51% {
    opacity: 1;
  }
}

@keyframes slide-start {
  49% {
    transform: translate(-100%);
  }
  50% {
    opacity: 0;
    transform: translate(100%);
  }
  51% {
    opacity: 1;
  }
}

@keyframes slide-up {
  49% {
    transform: translateY(-100%);
  }
  50% {
    opacity: 0;
    transform: translateY(100%);
  }
  51% {
    opacity: 1;
  }
}

@keyframes slide-down {
  49% {
    transform: translateY(100%);
  }
  50% {
    opacity: 0;
    transform: translateY(-100%);
  }
  51% {
    opacity: 1;
  }
}

// Blinking

.animate-blinking {
  animation: blinking 1s infinite;
}

@keyframes blinking {
  from {
    opacity: 0;
  }
}

// Disable pseudo elements on .animate-target when used inside .animate-underline parent

.animate-shake,
.animate-pulse,
.animate-rotate,
.animate-scale,
.animate-slide-end,
.animate-slide-start,
.animate-slide-up,
.animate-slide-down {
  .animate-target::after {
    display: none;
  }
}

// Move up and down infinite animation

.animate-up-down {
  animation: move-up-down 5s linear infinite;
}

@keyframes move-up-down {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-1rem);
  }
}

// Move down and up infinite animation

.animate-down-up {
  animation: move-down-up 5s linear infinite;
}

@keyframes move-down-up {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(1rem);
  }
}

// Spin infinite animation

.animate-spin {
  animation: spin 10s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  50% {
    transform: rotate(180deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

// Blink infinite animation

.animate-blink {
  animation: blink 1.75s linear infinite;
}

@keyframes blink {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

// Fade in animation (for Dropdowns)

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

// Fade up animation (for Dropdowns)

@keyframes fade-up {
  from {
    opacity: 0;
    transform: translateY(0.5rem);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

// Hover effects

.hover-effect-scale {
  --#{$prefix}transition-duration: 0.35s;
  --#{$prefix}transform-scale: 1.06;

  .hover-effect-target {
    transition: transform var(--#{$prefix}transition-duration) ease-in-out;
  }

  &:hover .hover-effect-target,
  &:focus-visible .hover-effect-target,
  &:focus-within .hover-effect-target {
    transform: scale(var(--#{$prefix}transform-scale));
  }
}

.hover-effect-opacity {
  --#{$prefix}transition-duration: 0.25s;

  .hover-effect-target {
    transition: visibility var(--#{$prefix}transition-duration) ease-in-out,
      opacity var(--#{$prefix}transition-duration) ease-in-out;
  }

  &:hover .hover-effect-target.opacity-0,
  &:focus-visible .hover-effect-target.opacity-0,
  &:focus-within .hover-effect-target.opacity-0 {
    visibility: visible !important;
    opacity: 1 !important;
  }

  &:hover .hover-effect-target.opacity-100,
  &:focus-visible .hover-effect-target.opacity-100,
  &:focus-within .hover-effect-target.opacity-100 {
    visibility: hidden !important;
    opacity: 0 !important;
  }
}

.hover-effect-scale.hover-effect-opacity {
  .hover-effect-target {
    transition: all var(--#{$prefix}transition-duration) ease-in-out;
  }
}

.hover-effect-underline:hover {
  text-decoration: underline !important;
  text-decoration-thickness: var(--#{$prefix}underline-thickness) !important;
}
